﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Dpy.Math.Geometry.Geometry2D
{
    public class Ray2D : ILineGeometry2D
    {
        #region Fields

        private readonly Line2D line;

        #endregion


        #region Properties

        public Vector2D this[double lineCoodinate]
        {
            get
            {
                return this.line[lineCoodinate];
            }
        }

        #endregion


        #region Constructor

        public Ray2D(Vector2D startPoint, Vector2D secondPoint)
        {
            this.line = new Line2D(startPoint, secondPoint);
        }

        #endregion


        #region Methods

        public Vector2D GetPointProjection(Vector2D point, out double lineCoordinate)
        {
            return this.line.GetPointProjection(point, out lineCoordinate);
        }

        public Vector2D IntersectWith(Line2D line)
        {
            double rayCoord, lineCoord;

            return this.IntersectWith(line, out rayCoord, out lineCoord);
        }

        public Vector2D IntersectWith(Line2D line, out double rayCoordinate, out double lineCoordinate)
        {
            Vector2D result = Line2D.Intersect(this.line, line, out rayCoordinate, out lineCoordinate);

            if (rayCoordinate >= 0)
            {
                return result;
            }

            return null;
        }

        public Vector2D[] IntersectWith(Circle circle)
        {
            double[] rayCoordinates;

            return this.IntersectWith(circle, out rayCoordinates);
        }

        public Vector2D[] IntersectWith(Circle circle, out double[] rayCoordinates)
        {
            List<Vector2D> intersections = new List<Vector2D>();
            List<double> rayCoords = new List<double>();

            double[] lineCoordinates;
            Vector2D[] lineIntersections = this.line.IntersectWith(circle, out lineCoordinates);

            for (int i = 0; i < lineIntersections.Length; i++)
            {
                if (lineCoordinates[i] >= 0)
                {
                    intersections.Add(lineIntersections[i]);
                    rayCoords.Add(lineCoordinates[i]);
                }
            }

            rayCoordinates = rayCoords.ToArray();

            return intersections.ToArray();
        }

        public Vector2D IntersectWith(Ray2D other)
        {
            double first, second;

            return Ray2D.Intersect(this, other, out first, out second);
        }

        public static Vector2D Intersect(Ray2D a, Ray2D b, out double rayCoordinateOnA, out double rayCoordinateOnB)
        {
            Vector2D result = Line2D.Intersect(a.line, b.line, out rayCoordinateOnA, out rayCoordinateOnB);

            if (rayCoordinateOnA >= 0 && rayCoordinateOnB >= 0)
            {
                return result;
            }

            return null;
        }

        public bool TryGetLineCoordinate(Vector2D point, out double lineCoordinate)
        {
            return this.line.TryGetLineCoordinate(point, out lineCoordinate);
        }

        #endregion


        #region Overriden methods

        public override string ToString()
        {
            return this.line.ToString();
        }

        #endregion
    }
}
